package drds.plus.executor.cursor.cursor.impl.common;

import drds.plus.executor.cursor.cursor_metadata.ColumnNameAndTableNameAndColumnIndexAndNextHolder;
import drds.plus.executor.cursor.cursor_metadata.CursorMetaData;
import drds.plus.executor.cursor.cursor_metadata.CursorMetaDataImpl;
import drds.plus.executor.row_values.ArrayRowValues;
import drds.plus.executor.row_values.RowValues;
import drds.plus.executor.utils.Utils;
import drds.plus.sql_process.abstract_syntax_tree.configuration.ColumnMetaData;
import drds.plus.sql_process.abstract_syntax_tree.expression.item.column.Column;
import drds.plus.sql_process.abstract_syntax_tree.expression.item.function.*;
import drds.plus.sql_process.abstract_syntax_tree.expression.order_by.OrderBy;
import drds.plus.sql_process.type.Type;
import drds.plus.sql_process.type.Types;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class RangeMaker {

    public Range makeRange(Filter filter, List<OrderBy> orderByList) {
        CursorMetaData cursorMetaData = createCursorMetaData(orderByList);
        Range range = new Range();
        range.from = new ArrayRowValues(orderByList.size(), cursorMetaData);
        range.to = new ArrayRowValues(orderByList.size(), cursorMetaData);
        //
        convertFilterToLowerAndTopLimit(cursorMetaData, range, filter);
        /**
         * 补齐最小最大值
         */
        setLimitMinMaxValueOfNullValue(range.from, false);
        setLimitMinMaxValueOfNullValue(range.to, true);
        return range;
    }

    public CursorMetaData createCursorMetaData(List<OrderBy> orderByList) {
        List<ColumnMetaData> columnMetaDataList = new ArrayList<ColumnMetaData>(orderByList.size());
        for (OrderBy orderBy : orderByList) {
            ColumnMetaData columnMetaData = Utils.getColumnMetaData(orderBy.getItem());
            columnMetaDataList.add(columnMetaData);
        }
        CursorMetaData cursorMetaData = CursorMetaDataImpl.buildCursorMetaData(columnMetaDataList, orderByList.size());
        return cursorMetaData;
    }

    /**
     * 多个可以有范围约束的值的列
     */
    protected void convertFilterToLowerAndTopLimit(CursorMetaData cursorMetaData, Range range, Filter filter) {
        if (filter instanceof BooleanFilter) {
            setLimitValue(cursorMetaData, range, filter);
        } else if (filter instanceof LogicalOperationFilter) {
            LogicalOperationFilter logicalOperationFilter = (LogicalOperationFilter) filter;
            if (logicalOperationFilter.getOperation() == Operation.or) {
                throw new IllegalStateException("or ? should not be here");
            }
            List<Filter> filterList = logicalOperationFilter.getFilterList();
            for (Filter $filter : filterList) {
                convertFilterToLowerAndTopLimit(cursorMetaData, range, $filter);
            }
        } else if (filter instanceof OrsFilter) {
            throw new IllegalStateException("or ? should not be here");
        }
    }

    protected void setLimitValue(CursorMetaData cursorMetaData, Range range, Filter filter) {
        BooleanFilter booleanFilter = (BooleanFilter) filter;
        switch (booleanFilter.getOperation()) {
            case less_than:
                setLimitValue(cursorMetaData, booleanFilter, range.to, new EqualValueProcessor() {

                    public Object process(Object object, Type type) {
                        return decr(object, type);
                    }
                });
                break;
            case less_than_or_equal:
                setLimitValue(cursorMetaData, booleanFilter, range.to, new EqualValueProcessor() {

                    public Object process(Object object, Type type) {
                        return object;
                    }
                });
                break;
            case equal:
                setLimitValue(cursorMetaData, booleanFilter, range.from, new EqualValueProcessor() {

                    public Object process(Object object, Type type) {
                        return object;
                    }
                });
                setLimitValue(cursorMetaData, booleanFilter, range.to, new EqualValueProcessor() {

                    public Object process(Object object, Type type) {
                        return object;
                    }
                });
                break;
            case greater_than:
                setLimitValue(cursorMetaData, booleanFilter, range.from, new EqualValueProcessor() {
                    public Object process(Object object, Type type) {
                        return incr(object, type);
                    }
                });
                break;
            case greater_than_or_equal:
                setLimitValue(cursorMetaData, booleanFilter, range.from, new EqualValueProcessor() {
                    public Object process(Object object, Type type) {
                        return object;
                    }
                });
                break;

            default:
                throw new IllegalArgumentException("not supported yet");
        }
    }

    protected void setLimitValue(CursorMetaData cursorMetaData, BooleanFilter booleanFilter, RowValues rowData, EqualValueProcessor equalValueProcessor) {
        Column column = Utils.getIColumn(booleanFilter.getColumn());
        Object value = booleanFilter.getValue();
        value = checkValueTypeWithFunction(value);
        value = equalValueProcessor.process(value, column.getType());
        Integer index = cursorMetaData.getIndex(column.getTableName(), column.getColumnName(), column.getAlias());
        rowData.setObject(index, value);
    }


    public Object incr(Object c, Type type) {
        if (type == null) {
            type = Types.getTypeOfObject(c); // 可能为null
        }

        return type.incr(c);
    }

    public Object decr(Object c, Type type) {
        if (type == null) {
            type = Types.getTypeOfObject(c); // 可能为null
        }
        return type.decr(c);
    }

    /**
     * @param v 不能是Function
     */
    protected Comparable checkValueTypeWithFunction(Object v) {
        if (v instanceof Function) {
            // 要计算还是一并放在最前边计算好
            throw new IllegalAccessError("impossible");
        }
        return (Comparable) v;
    }

    /**
     * 补齐最小最大值
     */
    protected void setLimitMinMaxValueOfNullValue(RowValues rowData, boolean max) {
        CursorMetaData cursorMetaData = rowData.getParentCursorMetaData();
        Iterator<ColumnNameAndTableNameAndColumnIndexAndNextHolder> iterator = cursorMetaData.columnNameAndTableNameAndColumnIndexAndNextHolderIterator();
        while (iterator.hasNext()) {
            ColumnNameAndTableNameAndColumnIndexAndNextHolder next = iterator.next();
            String columnName = next.getColumnName();
            List<ColumnMetaData> columnMetaDataList = rowData.getParentCursorMetaData().getColumnMetaDataList();
            // TODO shenxun : 如果条件是null。。。没处理。。应该在Comparator里面处理
            if (rowData.getObject(next.getIndex()) == null) {
                boolean find = false;
                for (ColumnMetaData columnMetaData : columnMetaDataList) {
                    if (columnName.equalsIgnoreCase(columnMetaData.getColumnName())) {
                        find = true;
                        rowData.setObject(next.getIndex(), getTypeMinMaxValue(max, columnMetaData.getType()));
                        break;
                    }
                }
                if (!find) {
                    throw new IllegalStateException(" can't find column columnName : " + columnName + " on . " + columnMetaDataList);
                }
            }
        }
    }

    public Object getTypeMinMaxValue(boolean max, Type type) {
        if (max) {
            return type.getMaxValue();
        } else {
            // 任何类型的最小值都是null;
            return type.getMinValue();
        }
    }

}
